﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;

namespace NanoMvvm
{
    public abstract class PropertyObservableBase : INotifyPropertyChanged
    {
        protected PropertyObservableBase()
        {
            if (NanoMvvmFramework.IsInitialized)
            {
                NanoMvvmFramework.Instance.Localization.RegisterViewModel(this);
            }
        }

        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        public bool IsInDesignMode
        {
            get
            {
                return RunModeResolver.InDesignMode;
            }
        }

        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public void VerifyPropertyName(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                return;
            }

            // Verify that the property name matches a real,
            // public, instance property on this object.
            var props = TypeDescriptor.GetProperties(this).Cast<PropertyDescriptor>().Select(prop => prop.Name).ToList();

            if (!props.Contains(propertyName))
            {
                throw new Exception("Property name non-existent: " + propertyName);
            }
        }

        internal void RefreshUiCulture(CultureInfo culture)
        {
            OnUiCultureChange(culture);
        }

        protected virtual void NotifyPropertyChanged(string propName)
        {
            VerifyPropertyName(propName);
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propName));
            }
        }

        protected virtual void NotifyPropertyChanged<T>(Expression<Func<T>> selectorExpression)
        {
            NotifyPropertyChanged(ExpressionResolver.GetMemberName(selectorExpression));
        }

        protected virtual bool SetProperty<T>(ref T field, T value, Expression<Func<T>> property)
        {
            if (!EqualityComparer<T>.Default.Equals(field, value))
            {
                field = value;
                NotifyPropertyChanged(property);
                return true;
            }

            return false;
        }

        protected virtual void OnUiCultureChange(CultureInfo culture)
        {
            NotifyPropertyChanged(string.Empty);
        }

        protected bool InitializeDesignTimeData()
        {
            if (IsInDesignMode)
            {
                OnDesignTimeInit();

                return true;
            }

            return false;
        }

        protected virtual void OnDesignTimeInit()
        {
        }
    }
}